﻿/*
 * The copyright statement below is for NLog.
 * See http://nlog-project.org for more information.

Copyright (c) 2004-2011 Jaroslaw Kowalski <jaak@jkowalski.net>

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

* Redistributions of source code must retain the above copyright notice,
  this list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

* Neither the name of Jaroslaw Kowalski nor the names of its
  contributors may be used to endorse or promote products derived from this
  software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
*/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Reflection;
using System.Windows.Forms;
using Authorit.API.Configuration;
using AuthoritExtensibility;
using PluginLogger;
using SyncHeadings.Properties;

namespace SyncHeadings
{
	/// <summary>
	/// Provides the user interface for the plug-in
	/// </summary>
	public partial class SyncHeadingsForm : Form
	{
		#region Fields (41) 

		private AuthoritEventArgs aitArgs;
		private string btnCancelText;
		private string btnCancelTooltip;
		private string btnSaveSettingsText;
		private string btnSaveSettingsTooltip;
		private string btnSyncText;
		private string btnSyncTooltip;
		private string chkHelpLbl;
		private string chkHelpTooltip;
		private string chkOverwriteLbl;
		private string chkOverwriteTooltip;
		private string chkPrintLbl;
		private string chkPrintTooltip;
		private string chkWebLbl;
		private string chkWebTooltip;
		private Config config;
		private string errorDialogTitle;
		private bool formShowIcon;
		private string formTitle;
		private string grpHeadingsLbl;
		private string grpHeadingsTooltip;
		private string lblObjectsSelected;
		private string lblObjectsSelectedTooltip;
		private string logFileName;
		private LoggerWrapper logger;
		private const string loggerName = "SyncHeadingsLogger";
		private string nlogConfigFile;
		private bool overwriteHeadings;
		private string progBarTooltip;
		private string saveSettingsDialogMessage;
		private string saveSettingsDialogTitle;
		private bool showVersion;
		private string syncCancelledMessage;
		private string syncCancelledTitle;
		private string syncCompleteMessage;
		private string syncCompleteTitle;
		private bool syncHelp;
		private string syncNoHeadingsMessage;
		private bool syncPrint;
		private bool syncWeb;
		private string versionFormat;

		#endregion Fields 

		#region Constructors (1) 

		/// <summary>
		/// Initializes a new instance of the <see cref="SyncHeadingsForm"/> class
		/// </summary>
		public SyncHeadingsForm(AuthoritEventArgs args, Config pluginConfig)
		{
			this.config = pluginConfig;
			nlogConfigFile = config.NLogConfigFileName;
			logFileName = config.LogFileName;
			logger = new LoggerWrapper(loggerName, nlogConfigFile, logFileName);
			try
			{
				InitializeComponent();
				aitArgs = args;
				logger.WriteInfo(LogEventType.OperationSuccess);
			}
			catch (Exception ex)
			{
				logger.WriteFatalException(LogEventType.OperationFailed, ex);
				throw;
			}
		}

		#endregion Constructors 

		#region Properties (1) 

		/// <summary>
		/// Gets or sets the Author-it arguments that contain database and user contexts
		/// </summary>
		public AuthoritEventArgs AitArgs
		{
			get { return aitArgs; }
			set { aitArgs = value; }
		}

		#endregion Properties 

		#region Methods (9) 

		// Public Methods (1) 

		/// <summary>
		/// Gets the version of the current assembly
		/// </summary>
		/// <returns>String containing the version of the assembly</returns>
		/// <remarks>The version string is in the format Major.Minor.Build.Revision</remarks>
		public string GetVersion()
		{
			Version v = Assembly.GetExecutingAssembly().GetName().Version;
			string version = string.Format(CultureInfo.InvariantCulture, "{0}.{1}.{2}.{3}", v.Major, v.Minor, v.Build, v.Revision);
			return version;
		}
		// Private Methods (8) 

		/// <summary>
		/// Closes the form without performing any further operations
		/// </summary>
		/// <param name="sender">Object that triggered the event</param>
		/// <param name="e">Arguments for the event</param>
		private void btnCancel_Click(object sender, EventArgs e)
		{
			btnCancel.Enabled = false;
			if (bw.IsBusy)
			{
				bw.CancelAsync();
			}
			else
			{
				this.DialogResult = System.Windows.Forms.DialogResult.Cancel;
				this.Close();
			}
		}

		/// <summary>
		/// Saves the current settings as the default settings
		/// </summary>
		/// <param name="sender">Object that triggered the event</param>
		/// <param name="e">Arguments for the event</param>
		private void btnSaveSettings_Click(object sender, EventArgs e)
		{
			try
			{
				Settings.Default.SyncHeadingHelp = chkHelp.Checked;
				Settings.Default.SyncHeadingPrint = chkPrint.Checked;
				Settings.Default.SyncHeadingWeb = chkWeb.Checked;
				Settings.Default.OverwriteHeadings = chkOverwrite.Checked;
				Settings.Default.Save();
				MessageBox.Show(saveSettingsDialogMessage, saveSettingsDialogTitle, MessageBoxButtons.OK, MessageBoxIcon.Information);
			}
			catch (Exception ex)
			{
				logger.WriteLog(NLog.LogLevel.Error, LogEventType.OperationFailed, ex.Message);
				MessageBox.Show(ex.Message, errorDialogTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}

		/// <summary>
		/// Launches a background thread on <see cref="bw"/> that synchronizes the specified headings on the selected topics.
		/// </summary>
		/// <param name="sender">Object that triggered the event</param>
		/// <param name="e">Arguments for the event</param>
		private void btnSync_Click(object sender, EventArgs e)
		{
			enableDisableControls(false);

			HeadingType headings = HeadingType.None;
			if (chkPrint.Checked)
			{
				headings |= HeadingType.Print;
			}
			if (chkHelp.Checked)
			{
				headings |= HeadingType.Help;
			}
			if (chkWeb.Checked)
			{
				headings |= HeadingType.Web;
			}

			if (headings != HeadingType.None)
			{
				List<object> bwArgs = new List<object>();
				bwArgs.Add(aitArgs);
				bwArgs.Add(headings);
				bwArgs.Add(chkOverwrite.Checked);
				bw.RunWorkerAsync(bwArgs);
			}
			else
			{
				MessageBox.Show(syncNoHeadingsMessage, syncCompleteTitle, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
				enableDisableControls(true);
			}
		}

		/// <summary>
		/// On a background thread, synchronizes the specified headings of the selected topics.
		/// </summary>
		/// <param name="sender">Object that triggered the event</param>
		/// <param name="e">Arguments for the event</param>
		private void bw_DoWork(object sender, DoWorkEventArgs e)
		{
			BackgroundWorker worker = sender as BackgroundWorker;
			List<object> bwArgs = (List<object>)e.Argument;
			AuthoritEventArgs authoritArgs = (AuthoritEventArgs)bwArgs[0];
			HeadingType headingsToSync = (HeadingType)bwArgs[1];
			bool overwrite = (bool)bwArgs[2];

			SyncHeadings sync = new SyncHeadings(authoritArgs, overwrite);
			for (int i = 0; i < authoritArgs.SelectedObjectIDs.Count; i++)
			{
				if (worker.CancellationPending)
				{
					e.Cancel = true;
					break;
				}
				else
				{
					sync.Synchronize(authoritArgs.SelectedObjectIDs[i], headingsToSync, overwrite);
					worker.ReportProgress((int)(i * 100 / authoritArgs.SelectedObjectIDs.Count));
				}
			}
		}

		/// <summary>
		/// Updates the user interface when <see cref="BackgroundWorker.ReportProgress(int)"/> is called.
		/// </summary>
		/// <param name="sender">Object that triggered the event</param>
		/// <param name="e">Arguments for the event</param>
		private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
		{
			progBar.PerformStep();
		}

		/// <summary>
		/// Informs the user that the background thread operation completed.
		/// </summary>
		/// <param name="sender">Object that triggered the event</param>
		/// <param name="e">Arguments for the event</param>
		private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
		{
			if (e.Error != null)
			{
				logger.WriteLog(NLog.LogLevel.Error, LogEventType.OperationFailed, aitArgs.Username, null, String.Empty, e.Error.Message);
			}
			else if (e.Cancelled)
			{
				logger.WriteLog(NLog.LogLevel.Warn, LogEventType.OperationCancelled, aitArgs.Username, null, String.Empty, syncCancelledMessage);
				MessageBox.Show(syncCancelledMessage, syncCancelledTitle, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
				this.DialogResult = System.Windows.Forms.DialogResult.Cancel;
				this.Close();
			}
			else
			{
				logger.WriteInfo(LogEventType.OperationSuccess, aitArgs.Username, null, String.Empty);
				progBar.Value = progBar.Maximum;
				MessageBox.Show(syncCompleteMessage, syncCompleteTitle, MessageBoxButtons.OK, MessageBoxIcon.Information);
				this.DialogResult = System.Windows.Forms.DialogResult.OK;
				this.Close();
			}
		}

		/// <summary>
		/// Enables or disables controls on the form.
		/// </summary>
		/// <param name="enabled">Specifies whether to enable the controls</param>
		/// <seealso cref="chkHelp"/>
		/// <seealso cref="chkPrint"/>
		/// <seealso cref="chkWeb"/>
		/// <seealso cref="btnSync"/>
		/// <seealso cref="chkOverwrite"/>
		/// <seealso cref="btnSaveSettings"/>
		private void enableDisableControls(bool enabled)
		{
			chkHelp.Enabled = enabled;
			chkPrint.Enabled = enabled;
			chkWeb.Enabled = enabled;
			btnSync.Enabled = enabled;
			chkOverwrite.Enabled = enabled;
			btnSaveSettings.Enabled = enabled;
		}

		/// <summary>
		/// Reads resources and settings for the form when it loads
		/// </summary>
		/// <param name="sender">Object that triggered the event</param>
		/// <param name="e">Arguments for the event</param>
		private void SyncHeadingsForm_Load(object sender, EventArgs e)
		{
			progBar.Minimum = 0;
			progBar.Maximum = aitArgs.SelectedObjectIDs.Count;
			progBar.Step = 1;

			try
			{
				formTitle = Resources.PluginFormTitle;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.PluginFormTitle), formTitle);
				formShowIcon = config.FormShowIcon;
				logger.WriteSettingRead(ReflectionUtility.GetPropertyName(() => Settings.Default.FormShowIcon), formShowIcon.ToString());
				this.Icon = Resources.sync_icon_16;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.sync_icon_16), this.Icon.ToString());

				showVersion = config.FormShowVersion;
				logger.WriteSettingRead(ReflectionUtility.GetPropertyName(() => Settings.Default.FormShowVersion), showVersion.ToString());

				if (showVersion)
				{
					versionFormat = Resources.VersionFormatString;
					logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.VersionFormatString), versionFormat);
				}

				syncPrint = Settings.Default.SyncHeadingPrint;
				logger.WriteSettingRead(ReflectionUtility.GetPropertyName(() => Settings.Default.SyncHeadingPrint), syncPrint.ToString());
				syncHelp = Settings.Default.SyncHeadingHelp;
				logger.WriteSettingRead(ReflectionUtility.GetPropertyName(() => Settings.Default.SyncHeadingHelp), syncHelp.ToString());
				syncWeb = Settings.Default.SyncHeadingWeb;
				logger.WriteSettingRead(ReflectionUtility.GetPropertyName(() => Settings.Default.SyncHeadingWeb), syncWeb.ToString());
				overwriteHeadings = Settings.Default.OverwriteHeadings;
				logger.WriteSettingRead(ReflectionUtility.GetPropertyName(() => Settings.Default.OverwriteHeadings), overwriteHeadings.ToString());

				grpHeadingsLbl = Resources.FormHeadingsGroupTitle;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.FormHeadingsGroupTitle), grpHeadingsLbl);
				grpHeadingsTooltip = Resources.FormHeadingsGroupTooltip;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.FormHeadingsGroupTooltip), grpHeadingsTooltip);
				chkPrintLbl = Resources.FormChkPrintLabel;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.FormChkPrintLabel), chkPrintLbl);
				chkPrintTooltip = Resources.FormChkPrintTooltip;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.FormChkPrintTooltip), chkPrintTooltip);
				chkHelpLbl = Resources.FormChkHelpLabel;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.FormChkHelpLabel), chkHelpLbl);
				chkHelpTooltip = Resources.FormChkHelpTooltip;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.FormChkHelpTooltip), chkHelpTooltip);
				chkWebLbl = Resources.FormChkWebLabel;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.FormChkWebLabel), chkWebLbl);
				chkWebTooltip = Resources.FormChkWebTooltip;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.FormChkWebTooltip), chkWebTooltip);

				chkOverwriteLbl = Resources.FormChkOverwriteLabel;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.FormChkOverwriteLabel), chkOverwriteLbl);

				chkOverwriteTooltip = Resources.FormChkOverwriteTooltip;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.FormChkOverwriteTooltip), chkOverwriteTooltip);

				syncCancelledMessage = Resources.DialogSyncCancelledMessage;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.DialogSyncCancelledMessage), syncCancelledMessage);

				syncCancelledTitle = Resources.DialogSyncCancelledTitle;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.DialogSyncCancelledTitle), syncCancelledTitle);

				lblObjectsSelected = Resources.FormLblSelectedObjects;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.FormLblSelectedObjects), lblObjectsSelected);
				lblObjectsSelectedTooltip = Resources.FormLblSelectedObjectsTooltip;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.FormLblSelectedObjectsTooltip), lblObjectsSelectedTooltip);

				progBarTooltip = Resources.FormProgbarTooltip;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.FormProgbarTooltip), progBarTooltip);

				btnCancelText = Resources.FormBtnCancelText;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.FormBtnCancelText), btnCancelText);
				btnCancelTooltip = Resources.FormBtnCancelTooltip;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.FormBtnCancelTooltip), btnCancelTooltip);
				btnSaveSettingsText = Resources.FormBtnSaveSettingsText;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.FormBtnSaveSettingsText), btnSaveSettingsText);
				btnSaveSettingsTooltip = Resources.FormBtnSaveSettingsTooltip;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.FormBtnSaveSettingsTooltip), btnSaveSettingsTooltip);
				btnSyncText = Resources.FormBtnSyncText;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.FormBtnSyncText), btnSyncText);
				btnSyncTooltip = Resources.FormBtnSyncTooltip;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.FormBtnSyncTooltip), btnSyncTooltip);
				errorDialogTitle = Resources.FormDialogErrorTitle;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.FormDialogErrorTitle), errorDialogTitle);

				saveSettingsDialogTitle = Resources.FormDialogSettingsSavedTitle;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.FormDialogSettingsSavedTitle), saveSettingsDialogTitle);
				saveSettingsDialogMessage = Resources.FormDialogSettingsSavedMessage;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.FormDialogSettingsSavedMessage), saveSettingsDialogMessage);

				syncCompleteTitle = Resources.DialogSyncCompleteTitle;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.DialogSyncCompleteTitle), syncCompleteTitle);
				syncCompleteMessage = Resources.DialogSyncCompleteMessage;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.DialogSyncCompleteMessage), syncCompleteMessage);
				syncNoHeadingsMessage = Resources.DialogSyncNoHeadingsMessage;
				logger.WriteResourceRead(ReflectionUtility.GetPropertyName(() => Resources.DialogSyncNoHeadingsMessage), syncNoHeadingsMessage);
			}
			catch (Exception ex)
			{
				logger.WriteFatalException(LogEventType.OperationFailed, ex);
				throw;
			}
			if (showVersion)
			{
				formTitle += String.Format(versionFormat, GetVersion());
			}

			this.Text = formTitle;
			this.ShowIcon = formShowIcon;

			lblObjectsSelected = String.Format(lblObjectsSelected, aitArgs.SelectedObjectIDs.Count);
			lblSelected.Text = lblObjectsSelected;
			lblSelected.ToolTipText = lblObjectsSelectedTooltip;

			progBar.ToolTipText = progBarTooltip;

			grpHeadings.Text = grpHeadingsLbl;
			tooltipMain.SetToolTip(grpHeadings, grpHeadingsTooltip);
			chkPrint.Text = chkPrintLbl;
			tooltipMain.SetToolTip(chkPrint, chkPrintTooltip);
			chkHelp.Text = chkHelpLbl;
			tooltipMain.SetToolTip(chkHelp, chkHelpTooltip);
			chkWeb.Text = chkWebLbl;
			tooltipMain.SetToolTip(chkWeb, chkWebTooltip);

			btnCancel.Text = btnCancelText;
			tooltipMain.SetToolTip(btnCancel, btnCancelTooltip);
			btnSync.Text = btnSyncText;
			tooltipMain.SetToolTip(btnSync, btnSyncTooltip);
			btnSaveSettings.Text = btnSaveSettingsText;
			tooltipMain.SetToolTip(btnSaveSettings, btnSaveSettingsTooltip);

			chkOverwrite.Text = chkOverwriteLbl;
			tooltipMain.SetToolTip(chkOverwrite, chkOverwriteTooltip);

			chkPrint.Checked = syncPrint;
			chkHelp.Checked = syncHelp;
			chkWeb.Checked = syncWeb;
			chkOverwrite.Checked = overwriteHeadings;

			logger.WriteInfo(LogEventType.OperationSuccess);
		}

		#endregion Methods 
	}
}